<?php
/**
 * CURL 类,支持链式写法
 * @authors yutent (yutent@doui.cc)
 * @date    2015-11-11 15:10:58
 *
 */

class Do_Curl {

    private $url = NULL;
    private $method = 'get';
    private $header = []; //要发送的头部信息
    private $para = []; //要发送的字段
    private $opts = [
                'has_header' => 0,//是否需要返回HTTP头信息
                'timeout' => 30,//单个CURL调用超时限制
                'post_by_raw' => 0, // 使用数据流发送
                'return_transfer' => 1,
            ];
    
    function __construct(){
        // return $this;
    }

    /**
     * [post 设置post发送方式/url]
     * @param  string $url [要请求的地址]
     */
    public function post($url = ''){
        $this->init_url($url);
        $this->method = 'post';
        return $this;
    }

    /**
     * [post 设置get发送方式/url]
     * @param  string $url [要请求的地址]
     */
    public function get($url = ''){
        $this->init_url($url);
        $this->method = 'get';
        return $this;
    }

    /**
     * [opt 设置一些额外的参数,如是否需要返回头部,超时等]
     * @param  [string] $key [要设置的参数]
     * @param  [string] $val [参数的值]
     * eg.
     * ->opt('timeout', 30)
     */
    public function opt($key, $val){
        if(isset($this->opts[$key]))
            $this->opts[$key] = $val;

        return $this;
    }

    /**
     * [set 设置头部信息]
     * @param [string/array] $arr [header, 字符串,或数组]
     * eg.
     *  ->set('Content-type:application/x-www-form-urlencoded')
     *  ->set(['Content-type' => 'application/x-www-form-urlencoded'])
     */
    public function set($arr){
        if(empty($arr))
            return;

        if(!is_array($arr)){
            list($key, $val) = explode(':', $arr);
            $this->header[$key] = $val;
        }else{
            array_merge($this->header, $arr);
        }
        return $this;
    }

    /**
     * [send 发送参数]
     * @param  [array] $arr [要发送的参数,以数组形式,程序会根据发送类型自动格式化]
     * eg.
     * ->send(['name' => 'admin', 'passwd' => '123456'])
     */
    public function send($arr){
        if(empty($arr))
            $this->para = '';
        elseif(!is_array($arr))
            $this->para = $arr;
        else
            $this->para = $this->init_param($arr);

        return $this;
    }


    /**
     * [end 结束请求]
     * @param  [Fn] $callback [回调函数]
     */
    public function end($callback){
        if($this->method === 'get')
            $this->url .= $this->para;

        $curl = curl_init();  
        curl_setopt($curl, CURLOPT_URL, $this->url);  
        curl_setopt($curl, CURLOPT_HEADER, $this->opts['has_header']);
        curl_setopt($curl, CURLOPT_HTTPHEADER, $this->header);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, $this->opts['return_transfer']);  
        curl_setopt($curl, CURLOPT_TIMEOUT, $this->opts['timeout']);

        if($this->method === 'post'){
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $this->para); 
        }

        $res = curl_exec($curl);
        curl_close($curl);

        $callback($res);
    }

    /**
     * [init_url 私有方法,初始化url]
     */
    private function init_url($url = ''){
        $url = trim($url);
        if(empty($url) || !strpos($url, 'http://') === 0 || !strpos($url, 'https://') === 0){
            D::log('wrong url');
            exit('wrong url');
        }
        $this->url = rtrim($url, '?');
        $this->url = $url;
    }

    /**
     * [init_param 私有方法,按发送类型格式化参数]
     * @param  [array] $arr [要发送的参数]
     */
    private function init_param($arr){
        $para = '?';
        if($this->method === 'get'){
            foreach ($arr as $k => $val) {
                $para .= $k  . '=' . urlencode($val) . '&';
            }
            $para = substr($para, 0, strlen($para) - 2); //去掉最后一个&字符
            $para = stripslashes($para); //去掉转义字符,如果存在
            $this->set('Content-type:application/x-www-form-urlencoded;charset=utf-8');
        }else{
            if($this->opts['post_by_raw']){
                $para = json_encode($arr);
                $this->set('Content-type:application/json;charset=utf-8');
            }else{
                $para = $arr;
                $this->set('Content-type:form-data;charset=utf-8');
            }
        }
        return $para;
    }

    /**
     * [init_header 私有方法,格式化头部信息]
     */
    private function init_header(){
        $hd = [];
        foreach ($this->header as $k => $val) {
            array_push($dh, $k  . ':' . $val);
        }
        return $hd;
    }
}